#include "tiffiop.h"

static int TIFFNoEncode( TIFF* tif, char* method ) {
  const TIFFCodec* c = TIFFFindCODEC( tif->tif_dir.td_compression );
  if( c ) {
    if( ! strncmp( c->name, "LZW", 3 ) ) {
      TIFFError( tif->tif_name, "%s %s 由于Unisys专利实施，编码不再实现", c->name, method );
    } else {
      TIFFError( tif->tif_name, "%s %s 编码未实现", c->name, method );
    }
  } else {
    TIFFError( tif->tif_name, "压缩方案 %u %s 编码未实现", tif->tif_dir.td_compression, method );
  }
  return ( -1 );
}

int _TIFFNoRowEncode( TIFF* tif, tidata_t pp, tsize_t cc, tsample_t s ) {
  ( void ) pp;
  ( void ) cc;
  ( void ) s;
  return ( TIFFNoEncode( tif, "scanline" ) );
}

int _TIFFNoStripEncode( TIFF* tif, tidata_t pp, tsize_t cc, tsample_t s ) {
  ( void ) pp;
  ( void ) cc;
  ( void ) s;
  return ( TIFFNoEncode( tif, "strip" ) );
}

int _TIFFNoTileEncode( TIFF* tif, tidata_t pp, tsize_t cc, tsample_t s ) {
  ( void ) pp;
  ( void ) cc;
  ( void ) s;
  return ( TIFFNoEncode( tif, "tile" ) );
}

static int TIFFNoDecode( TIFF* tif, char* method ) {
  const TIFFCodec* c = TIFFFindCODEC( tif->tif_dir.td_compression );
  if( c )
    TIFFError( tif->tif_name, "%s %s decoding is not implemented",
               c->name, method );
  else
    TIFFError( tif->tif_name,
               "Compression scheme %u %s decoding is not implemented",
               tif->tif_dir.td_compression, method );
  return ( -1 );
}

int _TIFFNoRowDecode( TIFF* tif, tidata_t pp, tsize_t cc, tsample_t s ) {
  ( void ) pp;
  ( void ) cc;
  ( void ) s;
  return ( TIFFNoDecode( tif, "scanline" ) );
}

int _TIFFNoStripDecode( TIFF* tif, tidata_t pp, tsize_t cc, tsample_t s ) {
  ( void ) pp;
  ( void ) cc;
  ( void ) s;
  return ( TIFFNoDecode( tif, "strip" ) );
}

int _TIFFNoTileDecode( TIFF* tif, tidata_t pp, tsize_t cc, tsample_t s ) {
  ( void ) pp;
  ( void ) cc;
  ( void ) s;
  return ( TIFFNoDecode( tif, "tile" ) );
}

int _TIFFNoSeek( TIFF* tif, uint32 off ) {
  ( void ) off;
  TIFFError( tif->tif_name, "压缩算法不支持随机访问" );
  return ( 0 );
}

int _TIFFNoPreCode( TIFF* tif, tsample_t s ) {
  ( void ) tif;
  ( void ) s;
  return ( 1 );
}

static int _TIFFtrue( TIFF* tif ) { ( void ) tif; return ( 1 ); }
static void _TIFFvoid( TIFF* tif ) { ( void ) tif; }

void _TIFFSetDefaultCompressionState( TIFF* tif ) {
  tif->tif_decodestatus = TRUE;
  tif->tif_setupdecode = _TIFFtrue;
  tif->tif_predecode = _TIFFNoPreCode;
  tif->tif_decoderow = _TIFFNoRowDecode;
  tif->tif_decodestrip = _TIFFNoStripDecode;
  tif->tif_decodetile = _TIFFNoTileDecode;
  tif->tif_encodestatus = TRUE;
  tif->tif_setupencode = _TIFFtrue;
  tif->tif_preencode = _TIFFNoPreCode;
  tif->tif_postencode = _TIFFtrue;
  tif->tif_encoderow = _TIFFNoRowEncode;
  tif->tif_encodestrip = _TIFFNoStripEncode;
  tif->tif_encodetile = _TIFFNoTileEncode;
  tif->tif_close = _TIFFvoid;
  tif->tif_seek = _TIFFNoSeek;
  tif->tif_cleanup = _TIFFvoid;
  tif->tif_defstripsize = _TIFFDefaultStripSize;
  tif->tif_deftilesize = _TIFFDefaultTileSize;
  tif->tif_flags &= ~TIFF_NOBITREV;
}

int TIFFSetCompressionScheme( TIFF* tif, int scheme ) {
  const TIFFCodec *c = TIFFFindCODEC( ( uint16 ) scheme );
  _TIFFSetDefaultCompressionState( tif );
  return ( c ? ( *c->init )( tif, scheme ) : 1 );
}

typedef struct _codec {
  struct _codec*  next;
  TIFFCodec*  info;
} codec_t;

static  codec_t* registeredCODECS = NULL;

const TIFFCodec* TIFFFindCODEC( uint16 scheme ) {
  const TIFFCodec* c;
  codec_t* cd;
  for( cd = registeredCODECS; cd; cd = cd->next )
    if( cd->info->scheme == scheme ) {
      return ( ( const TIFFCodec* ) cd->info );
    }
  for( c = _TIFFBuiltinCODECS; c->name; c++ )
    if( c->scheme == scheme ) {
      return ( c );
    }
  return ( ( const TIFFCodec* ) 0 );
}

TIFFCodec* TIFFRegisterCODEC( uint16 scheme, const char* name, TIFFInitMethod init ) {
  codec_t* cd = ( codec_t* ) _TIFFmalloc( sizeof( codec_t ) + sizeof( TIFFCodec ) + strlen( name ) + 1 );
  if( cd != NULL ) {
    cd->info = ( TIFFCodec* )( ( tidata_t ) cd + sizeof( codec_t ) );
    cd->info->name = ( char* )( ( tidata_t ) cd->info + sizeof( TIFFCodec ) );
    strcpy( cd->info->name, name );
    cd->info->scheme = scheme;
    cd->info->init = init;
    cd->next = registeredCODECS;
    registeredCODECS = cd;
  } else {
    TIFFError( "TIFFRegisterCODEC", "没有空间来注册压缩方案 %s", name );
    return NULL;
  }
  return ( cd->info );
}

void TIFFUnRegisterCODEC( TIFFCodec* c ) {
  codec_t* cd;
  codec_t** pcd;
  for( pcd = &registeredCODECS; ( cd = *pcd ); pcd = &cd->next )
    if( cd->info == c ) {
      *pcd = cd->next;
      _TIFFfree( cd );
      return;
    }
  TIFFError( "TIFFUnRegisterCODEC", "无法删除压缩方案 %s; 未注册", c->name );
}
